package net.ufrog.common.app;

import net.ufrog.common.converters.Converter;
import net.ufrog.common.exception.ServiceException;
import net.ufrog.common.utils.Files;
import net.ufrog.common.utils.Strings;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
 * 属性封装
 *
 * @author ultrafrog, ufrog.net@gmail.com
 * @version 0.1, 2017-07-06
 * @since 0.1
 */
public class PropertiesWrapper {

    private static final String DEFAULT_SEPARATOR = ".";

    /** 属性 */
    private Properties properties;

    /** 构造函数 */
    private PropertiesWrapper() {
        properties = new Properties();
    }

    /**
     * 放入内容
     *
     * @param key 键值
     * @param value 内容
     */
    public void put(Object key, Object value) {
        properties.put(key, value);
    }

    /**
     * 读取内容
     *
     * @param key 键值
     * @return 内容
     */
    public Object get(Object key) {
        return properties.get(key);
    }

    /**
     * 读取内容
     *
     * @param key 键值
     * @param defaultValue 默认值
     * @return 内容
     */
    public Object getOrDefault(Object key, Object defaultValue) {
        return properties.getOrDefault(key, defaultValue);
    }

    /**
     * 读取内容
     *
     * @param key 键值
     * @return 内容
     */
    public String getProperty(String key) {
        return properties.getProperty(key);
    }

    /**
     * 读取内容
     *
     * @param key 键值
     * @param defaultValue 默认值
     * @return 内容
     */
    public String getProperty(String key, String defaultValue) {
        return properties.getProperty(key, defaultValue);
    }

    /**
     * 读取内容属性
     *
     * @param prefix 前缀
     * @param separator 分隔符
     * @param needPrefix 是否需要前缀
     * @return 属性
     */
    public Properties getProperties(String prefix, String separator, Boolean needPrefix) {
        if (Strings.empty(prefix)) {
            return properties;
        } else {
            Properties props = new Properties();
            properties.stringPropertyNames().stream().filter(name -> name.startsWith(prefix + separator)).forEach(name -> {
                String key = needPrefix ? name : name.substring(prefix.length() + separator.length());
                props.put(key, properties.get(name));
            });
            return props;
        }
    }

    /**
     * 读取内容属性
     *
     * @param prefix 前缀
     * @return 属性
     */
    public Properties getProperties(String prefix) {
        return getProperties(prefix, DEFAULT_SEPARATOR, Boolean.FALSE);
    }

    /**
     * 读取内容属性
     *
     * @return 属性
     */
    public Properties getProperties() {
        return getProperties(null);
    }

    /**
     * 读取属性对象
     *
     * @param prefix 前缀
     * @param separator 分隔符
     * @param requestType 请求类型
     * @param <T> 请求范型
     * @return 属性对象
     */
    public <T> T getBean(String prefix, String separator, Class<T> requestType) {
        try {
            T result = requestType.newInstance();
            Properties props = getProperties(prefix, separator, Boolean.FALSE);
            PropertiesBeans.getPropertiesValues(requestType).forEach((field, pv) -> {
                try {
                    Object value;
                    if (field.getType() == Properties.class) {
                        value = Converter.convert(getProperties(prefix + separator + pv.value(), separator, Boolean.FALSE), null, Properties.class);
                    } else {
                        value = Converter.convert(props.get(pv.value()), pv.defaultValue(), field.getType());
                    }
                    if (!field.isAccessible()) field.setAccessible(true);
                    field.set(result, value);
                } catch (Exception e) {
                    throw new ServiceException(e.getMessage(), e);
                }
            });
            return result;
        } catch (Exception e) {
            throw new ServiceException(e.getMessage(), e);
        }
    }

    /**
     * 读取属性对象
     *
     * @param prefix 前缀
     * @param requestType 请求类型
     * @param <T> 请求范型
     * @return 属性对象
     */
    public <T> T getBean(String prefix, Class<T> requestType) {
        return getBean(prefix, DEFAULT_SEPARATOR, requestType);
    }

    /**
     * 创建属性封装
     *
     * @param path 文件路径
     * @return 属性封装
     */
    public static PropertiesWrapper create(String path) {
        try (InputStream inputStream = Files.getInputStream(path)) {
            return create(inputStream);
        } catch (IOException e) {
            throw new ServiceException(e.getMessage(), e);
        }
    }

    /**
     * 创建属性封装
     *
     * @param inputStream 输入流
     * @return 属性封装
     */
    public static PropertiesWrapper create(InputStream inputStream) {
        try {
            PropertiesWrapper propertiesWrapper = new PropertiesWrapper();
            propertiesWrapper.properties.load(inputStream);
            return propertiesWrapper;
        } catch (IOException e) {
            throw new ServiceException(e.getMessage(), e);
        }
    }
}
